namespace c3o.Framework.Web
{
    using System;
    using System.Xml;
    using System.Xml.Serialization;
	using System.Collections;
	using System.Collections.Specialized;

    public class Opml
    {
		public OpmlHead head;
		public OpmlBody body;

		public Opml()
		{
			this.head = new OpmlHead();
			this.body = new OpmlBody();
		}

		public Opml(XmlDocument xml)
        {
			this.head = new OpmlHead(xml, this);
			this.body = new OpmlBody(xml, this);
        }

		public XmlDocument GetXml()
		{
			// Create the document
			XmlDocument xml = new XmlDocument();

			// The Declaration
			xml.AppendChild(xml.CreateXmlDeclaration("1.0", "utf-8", null));

//			xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement); 

			// Create the root element
			XmlElement xmlOpml = xml.CreateElement("ompl");
			xmlOpml.SetAttribute("version", "1.0");			
			xml.AppendChild(xmlOpml);

			xmlOpml.AppendChild(this.head.GetXml(xml));
			xmlOpml.AppendChild(this.body.GetXml(xml));

			return xml;
		}
    }

	public class OpmlHead : StringDictionary
    {
        public string title;
		public Opml opml;

		public OpmlHead()		{}

		public OpmlHead(XmlDocument xml, Opml opml)
		{
			this.opml = opml;

			XmlNode rootNode = xml.DocumentElement.ChildNodes[0];			

			foreach (XmlNode node in rootNode.ChildNodes)
			{
				switch (node.Name)
				{
					case "title":
						this.title = node.InnerText;
						break;
					default:
						this.Add(node.Name, node.InnerText);
						break;
				}
			}
		}

		public XmlNode GetXml(XmlDocument xml)
		{						
			XmlNode XmlHead = xml.CreateElement("head");

			XmlNode XmlTitle = xml.CreateElement("title");
			XmlTitle.InnerText = this.title;			
			XmlHead.AppendChild(XmlTitle);

			foreach (string key in this.Keys)
			{
				XmlTitle = xml.CreateElement(key);
				XmlTitle.InnerText = this[key];
				XmlHead.AppendChild(XmlTitle);
			}

			return XmlHead;
		}
	}
    

	public class OpmlBody
    {				
		public OpmlOutline[] outlines;
		public Opml opml;

		public OpmlBody() { }

		public OpmlBody(XmlDocument xml, Opml opml)
		{
			this.opml = opml;

			// Get Body
			XmlNode rootNode = xml.DocumentElement.ChildNodes[1];

			ArrayList list = new ArrayList();

			foreach (XmlNode node in rootNode.ChildNodes)
			{
				OpmlOutline outline = new OpmlOutline(node, this);

				list.Add(outline);
			}

			this.outlines = (OpmlOutline[])list.ToArray(typeof(OpmlOutline));
		}

		public XmlNode GetXml(XmlDocument xml)
		{
			XmlNode xmlBody = xml.CreateElement("body");

			foreach (OpmlOutline item in this.outlines)
			{
				if (!item.isDeleted)
				{
					xmlBody.AppendChild(item.GetXml(xml));
				}
			}

			return xmlBody;
		}

		public void Add(OpmlOutline item)
		{
			item.body = this;

			ArrayList list;

			if (this.outlines != null)
			{
				list = new ArrayList(this.outlines);
			}
			else
			{
				list = new ArrayList();
			}

			list.Add(item);

			this.outlines = (OpmlOutline[])list.ToArray(typeof(OpmlOutline));
		}	
	}

	public class OpmlOutline : StringDictionary
    {
        public string text;
        public string type;
        public string url;
		public string image;
		public string search;
		public string replace;
		public OpmlOutline[] outlines;
		public OpmlOutline parent = null;
		public OpmlBody body = null;
		public bool isDeleted = false;

		public OpmlOutline(string text, string type, string url, string image, OpmlBody body, OpmlOutline parent)
		{
			this.text = text;
			this.type = type;
			this.url = url;
			this.parent = parent;
			this.body = body;
			this.image = image;
			this.search = null;
			this.replace = null;
		}

		public OpmlOutline(string text, string type, string url, string image, string search, string replace, OpmlBody body, OpmlOutline parent)
		{
			this.text = text;
			this.type = type;
			this.url = url;
			this.parent = parent;
			this.body = body;
			this.image = image;
			this.search = search;
			this.replace = replace;
		}

		public OpmlOutline(XmlNode parentNode, OpmlBody body )
		{
			this.body = body;

		    this.LoadFromXml(parentNode);
		}
		
		public OpmlOutline(XmlNode parentNode, OpmlOutline parent)
		{
			this.parent = parent;

			if (parent != null)
			{
				this.body = parent.body;
			}
			this.LoadFromXml(parentNode);
		}

		private void LoadFromXml(XmlNode parentNode)
		{
			ArrayList list = new ArrayList();

			// Create columns
			foreach (XmlAttribute attribute in parentNode.Attributes)
			{
				switch (attribute.Name.ToLower())
				{
					case "text":
						this.text = attribute.Value;
						break;
					case "type":
						this.type = attribute.Value;
						break;
					case "url":
						this.url = attribute.Value;
						break;
                    case "xmlurl":
						this.url = attribute.Value;
						break;
					case "image":
						this.image = attribute.Value;
						break;
					case "itunes:image_href":
						this.image = attribute.Value;
						break;
					case "search":
						this.search = attribute.Value;
						break;
					case "replace":
						this.replace = attribute.Value;
						break;
					default:
						this.Add(attribute.Name, attribute.Value);
						break;
				}
			}

			foreach (XmlNode node in parentNode.ChildNodes)
			{
				OpmlOutline outline = new OpmlOutline(node, this);
				list.Add(outline);
				//outline.body = this.body;
				//outline.parent = this;
			}

			this.outlines = (OpmlOutline[])list.ToArray(typeof(OpmlOutline));
		}


		public XmlNode GetXml(XmlDocument xml)
		{
			XmlElement xmlOutline = xml.CreateElement("outline");
			xmlOutline.SetAttribute("text", this.text);
			xmlOutline.SetAttribute("url",	this.url);
			xmlOutline.SetAttribute("image", this.image);
			xmlOutline.SetAttribute("type", this.type);
			xmlOutline.SetAttribute("search", this.search);
			xmlOutline.SetAttribute("replace", this.replace);

			foreach (string key in this.Keys)
			{
				//xmlOutline = xml.CreateElement(key);
				xmlOutline.SetAttribute(key, this[key]);
			}

			if (this.outlines != null)
			{
				foreach (OpmlOutline item in this.outlines)
				{
					if (!item.isDeleted)
					{
						xmlOutline.AppendChild(item.GetXml(xml));
					}
				}
			}			
			return xmlOutline;
		}

		public void Link(Opml opml)
		{
			this.outlines = opml.body.outlines;

			foreach (OpmlOutline outline in this.outlines)
			{
				outline.parent = this;
			}
		}

		public void Add(OpmlOutline item)
		{			
			ArrayList list;

			item.parent = this;
			item.body = this.body;

			if (this.outlines != null)
			{
				list = new ArrayList(this.outlines);
			}
			else
			{
				list = new ArrayList();
			}

			list.Add(item);

			this.outlines = (OpmlOutline[])list.ToArray(typeof(OpmlOutline));
		}

		public void Delete()
		{
			this.isDeleted = true;

			OpmlOutline[] parentlist = null;
//			ArrayList list = new ArrayList();

			if (this.parent == null)
			{
				if (this.body != null)
				{
					parentlist = this.body.outlines;
				}
			}
			else			
			{
				parentlist = this.parent.outlines;
			}

			if (parentlist != null)
			{
				ArrayList list = new ArrayList(parentlist);

				// Remove from list
				if (list.Contains(this))
				{
					list.Remove(this);
				}

				// Update the parent list
				parentlist = (OpmlOutline[])list.ToArray(typeof(OpmlOutline));
				
				this.parent = null;
				this.body = null;
			}
		}
	}
}